<!doctype html>



  


<html class="theme-next pisces use-motion">
<head>
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-PBHRK7');</script>
<!-- End Google Tag Manager -->
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>



<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />












  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />




  
  
  
  

  
    
    
  

  

  

  

  

  
    
    
    <link href="//fonts.googleapis.com/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
  






<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.4.0" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.0.2" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="前端 知识 面试," />








  <link rel="shortcut icon" type="image/x-icon" href="/favicon.ico?v=5.0.2" />






<meta name="description" content="1. 实现一个new操作符 来源：「你不知道的javascript」 英文版  new操作符做了这些事：  它创建了一个全新的对象。 它会被执行[[Prototype]]（也就是__proto__）链接。 它使this指向新创建的对象。。 通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。 如果函数没有返回对象类型Object(包含Functoin">
<meta name="keywords" content="前端 知识 面试">
<meta property="og:type" content="article">
<meta property="og:title" content="前端面试《第七篇》手写js常考知识">
<meta property="og:url" content="http://wurh.github.io/2019/03/31/20190404/index.html">
<meta property="og:site_name" content="华Ing&#39;s blog">
<meta property="og:description" content="1. 实现一个new操作符 来源：「你不知道的javascript」 英文版  new操作符做了这些事：  它创建了一个全新的对象。 它会被执行[[Prototype]]（也就是__proto__）链接。 它使this指向新创建的对象。。 通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。 如果函数没有返回对象类型Object(包含Functoin">
<meta property="og:locale" content="en">
<meta property="og:image" content="https://wurh.github.io/images/blogs/20190404/1.jpeg">
<meta property="og:image" content="https://wurh.github.io/images/blogs/20190404/2.jpeg">
<meta property="og:image" content="https://wurh.github.io/images/blogs/20190404/3.jpeg">
<meta property="og:updated_time" content="2019-07-12T06:10:38.192Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="前端面试《第七篇》手写js常考知识">
<meta name="twitter:description" content="1. 实现一个new操作符 来源：「你不知道的javascript」 英文版  new操作符做了这些事：  它创建了一个全新的对象。 它会被执行[[Prototype]]（也就是__proto__）链接。 它使this指向新创建的对象。。 通过new创建的每个对象将最终被[[Prototype]]链接到这个函数的prototype对象上。 如果函数没有返回对象类型Object(包含Functoin">
<meta name="twitter:image" content="https://wurh.github.io/images/blogs/20190404/1.jpeg">



<script type="text/javascript" id="hexo.configuration">
  var NexT = window.NexT || {};
  var CONFIG = {
    scheme: 'Pisces',
    sidebar: {"position":"left","display":"post"},
    fancybox: true,
    motion: true,
    duoshuo: {
      userId: '0',
      author: 'Author'
    }
  };
</script>




  <link rel="canonical" href="http://wurh.github.io/2019/03/31/20190404/"/>


  <title> 前端面试《第七篇》手写js常考知识 | 华Ing's blog </title>
</head>

<body itemscope itemtype="//schema.org/WebPage" lang="en">
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-PBHRK7"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) -->

  










  
  
    
  

<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-69412379-1', 'auto');
  ga('send', 'pageview');

</script>

  <script>
  var _hmt = _hmt || [];
  (function() {
    var hm = document.createElement("script");
    hm.src = "https://hm.baidu.com/hm.js?b3ddfb8655d8b77429e04c7a4d5bcbc1";
    var s = document.getElementsByTagName("script")[0];
    s.parentNode.insertBefore(hm, s);
  })();
  </script>


  <div class="container one-collumn sidebar-position-left page-post-detail ">
    <div class="headband"></div>

    <header id="header" class="header" itemscope itemtype="//schema.org/WPHeader">
      <div class="header-inner"><div class="site-meta ">
  

  <div class="custom-logo-site-title">
    <a href="/"  class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <span class="site-title">华Ing's blog</span>
      <span class="logo-line-after"><i></i></span>
    </a>
  </div>
  <p class="site-subtitle">harder and harder</p>
</div>

<div class="site-nav-toggle">
  <button>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
    <span class="btn-bar"></span>
  </button>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
            Home
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories" rel="section">
            
            Categories
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives" rel="section">
            
            Archives
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags" rel="section">
            
            Tags
          </a>
        </li>
      

      
    </ul>
  

  
</nav>

 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  
  

  
  
  

  <article class="post post-type-normal " itemscope itemtype="//schema.org/Article">

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">
            
            
              
                前端面试《第七篇》手写js常考知识
              
            
          </h1>
        

        <div class="post-meta">
          <span class="post-time">
            <span class="post-meta-item-icon">
              <i class="fa fa-calendar-o"></i>
            </span>
            <span class="post-meta-item-text">Posted on</span>
            <time itemprop="dateCreated" datetime="2019-03-31T08:20:00+08:00" content="2019-03-31">
              2019-03-31
            </time>
          </span>

          
            <span class="post-category" >
              &nbsp; | &nbsp;
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">In</span>
              
                <span itemprop="about" itemscope itemtype="https://schema.org/Thing">
                  <a href="/categories/前端面试/" itemprop="url" rel="index">
                    <span itemprop="name">前端面试</span>
                  </a>
                </span>

                
                

              
            </span>
          

          
            
              <span class="post-comments-count">
                &nbsp; | &nbsp;
                <a href="/2019/03/31/20190404/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count ds-thread-count" data-thread-key="2019/03/31/20190404/" itemprop="commentsCount"></span>
                </a>
              </span>
            
          

          

          
          

          
        </div>
      </header>
    


    <div class="post-body" itemprop="articleBody">

      
      

      
        <h2 id="1-实现一个new操作符"><a href="#1-实现一个new操作符" class="headerlink" title="1. 实现一个new操作符"></a>1. 实现一个<code>new</code>操作符</h2><blockquote>
<p><a href="https://link.juejin.im?target=http%3A%2F%2Fblog.ifyouseewendy.com%2Fblog%2F2017%2F07%2F03%2Freview-you-dont-know-js-this-and-object-prototypes%2F%23what-happened-when-we-callnew-" target="_blank" rel="noopener">来源：「你不知道的javascript」 英文版</a></p>
</blockquote>
<p><code>new</code>操作符做了这些事：</p>
<ul>
<li>它创建了一个全新的对象。</li>
<li>它会被执行<code>[[Prototype]]</code>（也就是<code>__proto__</code>）链接。</li>
<li>它使<code>this</code>指向新创建的对象。。</li>
<li>通过<code>new</code>创建的每个对象将最终被<code>[[Prototype]]</code>链接到这个函数的<code>prototype</code>对象上。</li>
<li>如果函数没有返回对象类型<code>Object</code>(包含<code>Functoin, Array, Date, RegExg, Error</code>)，那么<code>new</code>表达式中的函数调用将返回该对象引用。</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">New</span>(<span class="params">func</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> res = &#123;&#125;;</span><br><span class="line">    <span class="keyword">if</span> (func.prototype !== <span class="literal">null</span>) &#123;</span><br><span class="line">        res.__proto__ = func.prototype;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">var</span> ret = func.apply(res, <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>, <span class="number">1</span>));</span><br><span class="line">    <span class="keyword">if</span> ((<span class="keyword">typeof</span> ret === <span class="string">"object"</span> || <span class="keyword">typeof</span> ret === <span class="string">"function"</span>) &amp;&amp; ret !== <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> ret;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> obj = New(A, <span class="number">1</span>, <span class="number">2</span>);</span><br><span class="line"><span class="comment">// equals to</span></span><br><span class="line"><span class="keyword">var</span> obj = <span class="keyword">new</span> A(<span class="number">1</span>, <span class="number">2</span>);</span><br></pre></td></tr></table></figure>
<h2 id="2-实现一个JSON-stringify"><a href="#2-实现一个JSON-stringify" class="headerlink" title="2. 实现一个JSON.stringify"></a>2. 实现一个<code>JSON.stringify</code></h2><blockquote>
<p><code>JSON.stringify(value[, replacer [, space]])</code>：</p>
</blockquote>
<ul>
<li><code>Boolean | Number| String</code> 类型会自动转换成对应的原始值。</li>
<li><code>undefined</code>、任意函数以及<code>symbol</code>，会被忽略（出现在非数组对象的属性值中时），或者被转换成 <code>null</code>（出现在数组中时）。</li>
<li>不可枚举的属性会被忽略</li>
<li>如果一个对象的属性值通过某种间接的方式指回该对象本身，即循环引用，属性也会被忽略。</li>
</ul>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">jsonStringify</span>(<span class="params">obj</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> type = <span class="keyword">typeof</span> obj;</span><br><span class="line">    <span class="keyword">if</span> (type !== <span class="string">"object"</span> || type === <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span> (<span class="regexp">/string|undefined|function/</span>.test(type)) &#123;</span><br><span class="line">            obj = <span class="string">'"'</span> + obj + <span class="string">'"'</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">String</span>(obj);</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="keyword">let</span> json = []</span><br><span class="line">        arr = (obj &amp;&amp; obj.constructor === <span class="built_in">Array</span>);</span><br><span class="line">        <span class="keyword">for</span> (<span class="keyword">let</span> k <span class="keyword">in</span> obj) &#123;</span><br><span class="line">            <span class="keyword">let</span> v = obj[k];</span><br><span class="line">            <span class="keyword">let</span> type = <span class="keyword">typeof</span> v;</span><br><span class="line">            <span class="keyword">if</span> (<span class="regexp">/string|undefined|function/</span>.test(type)) &#123;</span><br><span class="line">                v = <span class="string">'"'</span> + v + <span class="string">'"'</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> <span class="keyword">if</span> (type === <span class="string">"object"</span>) &#123;</span><br><span class="line">                v = jsonStringify(v);</span><br><span class="line">            &#125;</span><br><span class="line">            json.push((arr ? <span class="string">""</span> : <span class="string">'"'</span> + k + <span class="string">'":'</span>) + <span class="built_in">String</span>(v));</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> (arr ? <span class="string">"["</span> : <span class="string">"&#123;"</span>) + <span class="built_in">String</span>(json) + (arr ? <span class="string">"]"</span> : <span class="string">"&#125;"</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">jsonStringify(&#123;<span class="attr">x</span> : <span class="number">5</span>&#125;) <span class="comment">// "&#123;"x":5&#125;"</span></span><br><span class="line">jsonStringify([<span class="number">1</span>, <span class="string">"false"</span>, <span class="literal">false</span>]) <span class="comment">// "[1,"false",false]"</span></span><br><span class="line">jsonStringify(&#123;<span class="attr">b</span>: <span class="literal">undefined</span>&#125;) <span class="comment">// "&#123;"b":"undefined"&#125;"</span></span><br></pre></td></tr></table></figure>
<h2 id="3-实现一个JSON-parse"><a href="#3-实现一个JSON-parse" class="headerlink" title="3. 实现一个JSON.parse"></a>3. 实现一个<code>JSON.parse</code></h2><blockquote>
<p><code>JSON.parse(text[, reviver])</code></p>
</blockquote>
<p>用来解析JSON字符串，构造由字符串描述的JavaScript值或对象。提供可选的reviver函数用以在返回之前对所得到的对象执行变换(操作)。</p>
<h3 id="3-1-第一种：直接调用-eval"><a href="#3-1-第一种：直接调用-eval" class="headerlink" title="3.1 第一种：直接调用 eval"></a>3.1 第一种：直接调用 eval</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">jsonParse</span>(<span class="params">opt</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">eval</span>(<span class="string">'('</span> + opt + <span class="string">')'</span>);</span><br><span class="line">&#125;</span><br><span class="line">jsonParse(jsonStringify(&#123;<span class="attr">x</span> : <span class="number">5</span>&#125;))</span><br><span class="line"><span class="comment">// Object &#123; x: 5&#125;</span></span><br><span class="line">jsonParse(jsonStringify([<span class="number">1</span>, <span class="string">"false"</span>, <span class="literal">false</span>]))</span><br><span class="line"><span class="comment">// [1, "false", falsr]</span></span><br><span class="line">jsonParse(jsonStringify(&#123;<span class="attr">b</span>: <span class="literal">undefined</span>&#125;))</span><br><span class="line"><span class="comment">// Object &#123; b: "undefined"&#125;</span></span><br></pre></td></tr></table></figure>
<blockquote>
<p>避免在不必要的情况下使用 <code>eval</code>，eval() 是一个危险的函数， 他执行的代码拥有着执行者的权利。如果你用 eval()运行的字符串代码被恶意方（不怀好意的人）操控修改，您最终可能会在您的网页/扩展程序的权限下，在用户计算机上运行恶意代码。</p>
</blockquote>
<p><strong>它会执行JS代码，有XSS漏洞。</strong></p>
<p><strong>如果你只想记这个方法，就得对参数json做校验。</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> rx_one = <span class="regexp">/^[\],:&#123;&#125;\s]*$/</span>;</span><br><span class="line"><span class="keyword">var</span> rx_two = <span class="regexp">/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]&#123;4&#125;)/g</span>;</span><br><span class="line"><span class="keyword">var</span> rx_three = <span class="regexp">/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g</span>;</span><br><span class="line"><span class="keyword">var</span> rx_four = <span class="regexp">/(?:^|:|,)(?:\s*\[)+/g</span>;</span><br><span class="line"><span class="keyword">if</span> (</span><br><span class="line">    rx_one.test(</span><br><span class="line">        json</span><br><span class="line">            .replace(rx_two, <span class="string">"@"</span>)</span><br><span class="line">            .replace(rx_three, <span class="string">"]"</span>)</span><br><span class="line">            .replace(rx_four, <span class="string">""</span>)</span><br><span class="line">    )</span><br><span class="line">) &#123;</span><br><span class="line">    <span class="keyword">var</span> obj = <span class="built_in">eval</span>(<span class="string">"("</span> +json + <span class="string">")"</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="3-2-第二种：Function"><a href="#3-2-第二种：Function" class="headerlink" title="3.2 第二种：Function"></a>3.2 第二种：Function</h3><blockquote>
<p>来源 <a href="https://link.juejin.im?target=https%3A%2F%2Fimys.net%2F20151222%2Feval-with-new-function.html" target="_blank" rel="noopener">神奇的eval()与new Function()</a></p>
</blockquote>
<p>核心：<code>Function</code>与<code>eval</code>有相同的字符串参数特性。</p>
<blockquote>
<p><code>var func = new Function(arg1, arg2, ..., functionBody);</code></p>
</blockquote>
<p>在转换JSON的实际应用中，只需要这么做。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> jsonStr = <span class="string">'&#123; "age": 20, "name": "jack" &#125;'</span></span><br><span class="line"><span class="keyword">var</span> json = (<span class="keyword">new</span> <span class="built_in">Function</span>(<span class="string">'return '</span> + jsonStr))();</span><br></pre></td></tr></table></figure>
<p><code>eval</code> 与 <code>Function</code> 都有着动态编译js代码的作用，但是在实际的编程中并不推荐使用。</p>
<p><strong>这里是面向面试编程，写这两种就够了。至于第三，第四种，涉及到繁琐的递归和状态机相关原理，具体可以看：</strong></p>
<blockquote>
<p><a href="https://link.juejin.im?target=https%3A%2F%2Fgithub.com%2Fyoungwind%2Fblog%2Fissues%2F115" target="_blank" rel="noopener">《JSON.parse 三种实现方式》</a></p>
</blockquote>
<h2 id="4-实现一个call或-apply"><a href="#4-实现一个call或-apply" class="headerlink" title="4. 实现一个call或 apply"></a>4. 实现一个<code>call</code>或 <code>apply</code></h2><p><code>call</code>语法：</p>
<blockquote>
<p><code>fun.call(thisArg, arg1, arg2, ...)</code>，调用一个函数, 其具有一个指定的this值和分别地提供的参数(参数的列表)。</p>
</blockquote>
<p><code>apply</code>语法：</p>
<blockquote>
<p><code>func.apply(thisArg, [argsArray])</code>，调用一个函数，以及作为一个数组（或类似数组对象）提供的参数。</p>
</blockquote>
<h3 id="4-1-Function-call按套路实现"><a href="#4-1-Function-call按套路实现" class="headerlink" title="4.1 Function.call按套路实现"></a>4.1 <code>Function.call</code>按套路实现</h3><p><code>call</code>核心：</p>
<ul>
<li>将函数设为对象的属性</li>
<li>执行&amp;删除这个函数</li>
<li>指定<code>this</code>到函数并传入给定参数执行函数</li>
<li>如果不传入参数，默认指向为 window</li>
</ul>
<p>为啥说是套路实现呢？因为真实面试中，面试官很喜欢让你逐步地往深考虑，这时候你可以反套路他，先写个简单版的：</p>
<h3 id="4-1-1-简单版"><a href="#4-1-1-简单版" class="headerlink" title="4.1.1 简单版"></a>4.1.1 简单版</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> foo = &#123;</span><br><span class="line">    value: <span class="number">1</span>,</span><br><span class="line">    bar: <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="keyword">this</span>.value)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">foo.bar() <span class="comment">// 1</span></span><br></pre></td></tr></table></figure>
<h3 id="4-1-2-完善版"><a href="#4-1-2-完善版" class="headerlink" title="4.1.2 完善版"></a>4.1.2 完善版</h3><p>当面试官有进一步的发问，或者此时你可以假装思考一下。然后写出以下版本：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Function</span>.prototype.call2 = <span class="function"><span class="keyword">function</span>(<span class="params">content = window</span>) </span>&#123;</span><br><span class="line">    content.fn = <span class="keyword">this</span>;</span><br><span class="line">    <span class="keyword">let</span> args = [...arguments].slice(<span class="number">1</span>);</span><br><span class="line">    <span class="keyword">let</span> result = content.fn(...args);</span><br><span class="line">    <span class="keyword">delete</span> content.fn;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> foo = &#123;</span><br><span class="line">    value: <span class="number">1</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">bar</span>(<span class="params">name, age</span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(name)</span><br><span class="line">    <span class="built_in">console</span>.log(age)</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="keyword">this</span>.value);</span><br><span class="line">&#125;</span><br><span class="line">bar.call2(foo, <span class="string">'black'</span>, <span class="string">'18'</span>) <span class="comment">// black 18 1</span></span><br></pre></td></tr></table></figure>
<h3 id="4-2-Function-apply的模拟实现"><a href="#4-2-Function-apply的模拟实现" class="headerlink" title="4.2 Function.apply的模拟实现"></a>4.2 <code>Function.apply</code>的模拟实现</h3><p><code>apply()</code>的实现和<code>call()</code>类似，只是参数形式不同。直接贴代码吧：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Function</span>.prototype.apply2 = <span class="function"><span class="keyword">function</span>(<span class="params">context = window</span>) </span>&#123;</span><br><span class="line">    context.fn = <span class="keyword">this</span></span><br><span class="line">    <span class="keyword">let</span> result;</span><br><span class="line">    <span class="comment">// 判断是否有第二个参数</span></span><br><span class="line">    <span class="keyword">if</span>(<span class="built_in">arguments</span>[<span class="number">1</span>]) &#123;</span><br><span class="line">        result = context.fn(...arguments[<span class="number">1</span>])</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        result = context.fn()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">delete</span> context.fn()</span><br><span class="line">    <span class="keyword">return</span> result</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="5-实现一个Function-bind"><a href="#5-实现一个Function-bind" class="headerlink" title="5. 实现一个Function.bind()"></a>5. 实现一个<code>Function.bind()</code></h2><p><code>bind()</code>方法:</p>
<blockquote>
<p>会创建一个新函数。当这个新函数被调用时，bind() 的第一个参数将作为它运行时的 this，之后的一序列参数将会在传递的实参前传入作为它的参数。(来自于 MDN )</p>
</blockquote>
<p>此外，<code>bind</code>实现需要考虑实例化后对原型链的影响。</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">Function</span>.prototype.bind2 = <span class="function"><span class="keyword">function</span>(<span class="params">content</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">typeof</span> <span class="keyword">this</span> != <span class="string">"function"</span>) &#123;</span><br><span class="line">        <span class="keyword">throw</span> <span class="built_in">Error</span>(<span class="string">"not a function"</span>)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// 若没问参数类型则从这开始写</span></span><br><span class="line">    <span class="keyword">let</span> fn = <span class="keyword">this</span>;</span><br><span class="line">    <span class="keyword">let</span> args = [...arguments].slice(<span class="number">1</span>);</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">let</span> resFn = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> fn.apply(<span class="keyword">this</span> <span class="keyword">instanceof</span> resFn ? <span class="keyword">this</span> : content,args.concat(...arguments) )</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">tmp</span>(<span class="params"></span>) </span>&#123;&#125;</span><br><span class="line">    tmp.prototype = <span class="keyword">this</span>.prototype;</span><br><span class="line">    resFn.prototype = <span class="keyword">new</span> tmp();</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">return</span> resFn;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="6-实现一个继承"><a href="#6-实现一个继承" class="headerlink" title="6. 实现一个继承"></a>6. 实现一个继承</h2><p><strong>寄生组合式继承</strong></p>
<p>一般只建议写这种，因为其它方式的继承会在一次实例中调用两次父类的构造函数或有其它缺点。</p>
<p>核心实现是：<strong>用一个 <code>F</code> 空的构造函数去取代执行了 <code>Parent</code> 这个构造函数。</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Parent</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.name = name;</span><br><span class="line">&#125;</span><br><span class="line">Parent.prototype.sayName = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'parent name:'</span>, <span class="keyword">this</span>.name);</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Child</span>(<span class="params">name, parentName</span>) </span>&#123;</span><br><span class="line">    Parent.call(<span class="keyword">this</span>, parentName);  </span><br><span class="line">    <span class="keyword">this</span>.name = name;    </span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">create</span>(<span class="params">proto</span>) </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">F</span>(<span class="params"></span>)</span>&#123;&#125;</span><br><span class="line">    F.prototype = proto;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> F();</span><br><span class="line">&#125;</span><br><span class="line">Child.prototype = create(Parent.prototype);</span><br><span class="line">Child.prototype.sayName = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'child name:'</span>, <span class="keyword">this</span>.name);</span><br><span class="line">&#125;</span><br><span class="line">Child.prototype.constructor = Child;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">var</span> parent = <span class="keyword">new</span> Parent(<span class="string">'father'</span>);</span><br><span class="line">parent.sayName();    <span class="comment">// parent name: father</span></span><br><span class="line">    </span><br><span class="line"><span class="keyword">var</span> child = <span class="keyword">new</span> Child(<span class="string">'son'</span>, <span class="string">'father'</span>);</span><br></pre></td></tr></table></figure>
<h2 id="7-实现一个JS函数柯里化"><a href="#7-实现一个JS函数柯里化" class="headerlink" title="7. 实现一个JS函数柯里化"></a>7. 实现一个JS函数柯里化</h2><p><strong>什么是柯里化？</strong></p>
<blockquote>
<p>在计算机科学中，柯里化（Currying）是把接受多个参数的函数变换成接受一个单一参数（最初函数的第一个参数）的函数，并且返回接受余下的参数且返回结果的新函数的技术。</p>
</blockquote>
<p><strong>函数柯里化的主要作用和特点就是参数复用、提前返回和延迟执行。</strong></p>
<h3 id="7-1-通用版"><a href="#7-1-通用版" class="headerlink" title="7.1 通用版"></a>7.1 通用版</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">curry</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> args = <span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>);</span><br><span class="line">    <span class="keyword">var</span> fn = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">var</span> newArgs = args.concat(<span class="built_in">Array</span>.prototype.slice.call(<span class="built_in">arguments</span>));</span><br><span class="line">        <span class="keyword">return</span> multi.apply(<span class="keyword">this</span>, newArgs);</span><br><span class="line">    &#125;</span><br><span class="line">    fn.toString = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> args.reduce(<span class="function"><span class="keyword">function</span>(<span class="params">a, b</span>) </span>&#123;</span><br><span class="line">            <span class="keyword">return</span> a * b;</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> fn;</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">multiFn</span>(<span class="params">a, b, c</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> a * b * c;</span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="keyword">var</span> multi = curry(multiFn);</span><br><span class="line">    </span><br><span class="line">multi(<span class="number">2</span>)(<span class="number">3</span>)(<span class="number">4</span>);</span><br><span class="line">multi(<span class="number">2</span>,<span class="number">3</span>,<span class="number">4</span>);</span><br><span class="line">multi(<span class="number">2</span>)(<span class="number">3</span>,<span class="number">4</span>);</span><br><span class="line">multi(<span class="number">2</span>,<span class="number">3</span>)(<span class="number">4</span>);</span><br></pre></td></tr></table></figure>
<h3 id="7-2-ES6骚写法"><a href="#7-2-ES6骚写法" class="headerlink" title="7.2 ES6骚写法"></a>7.2 <code>ES6</code>骚写法</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> curry = <span class="function">(<span class="params">fn, arr = []</span>) =&gt;</span> (...args) =&gt; (</span><br><span class="line">  arg =&gt; arg.length === fn.length</span><br><span class="line">    ? fn(...arg)</span><br><span class="line">    : curry(fn, arg)</span><br><span class="line">)([...arr, ...args])</span><br><span class="line">    </span><br><span class="line"><span class="keyword">let</span> curryTest=curry(<span class="function">(<span class="params">a,b,c,d</span>)=&gt;</span>a+b+c+d)</span><br><span class="line">curryTest(<span class="number">1</span>,<span class="number">2</span>,<span class="number">3</span>)(<span class="number">4</span>) <span class="comment">//返回10</span></span><br><span class="line">curryTest(<span class="number">1</span>,<span class="number">2</span>)(<span class="number">4</span>)(<span class="number">3</span>) <span class="comment">//返回10</span></span><br><span class="line">curryTest(<span class="number">1</span>,<span class="number">2</span>)(<span class="number">3</span>,<span class="number">4</span>) <span class="comment">//返回10</span></span><br></pre></td></tr></table></figure>
<h2 id="8-手写一个Promise-中高级必考"><a href="#8-手写一个Promise-中高级必考" class="headerlink" title="8. 手写一个Promise(中高级必考)"></a>8. 手写一个<code>Promise</code>(中高级必考)</h2><p>我们来过一遍<code>Promise/A+</code>规范：</p>
<ul>
<li>三种状态<code>pending| fulfilled(resolved) | rejected</code></li>
<li>当处于<code>pending</code>状态的时候，可以转移到<code>fulfilled(resolved)</code>或者<code>rejected</code>状态</li>
<li>当处于<code>fulfilled(resolved)</code>状态或者<code>rejected</code>状态的时候，就不可变。</li>
</ul>
<ol>
<li><p>必须有一个<code>then</code>异步执行方法，<code>then</code>接受两个参数且必须返回一个promise：</p>
<p>// onFulfilled 用来接收promise成功的值<br>// onRejected 用来接收promise失败的原因<br>promise1=promise.then(onFulfilled, onRejected);<br>复制代码</p>
</li>
</ol>
<h3 id="8-1-Promise的流程图分析"><a href="#8-1-Promise的流程图分析" class="headerlink" title="8.1 Promise的流程图分析"></a>8.1 <code>Promise</code>的流程图分析</h3><p><img src="https://wurh.github.io/images/blogs/20190404/1.jpeg" alt=""></p>
<p>来回顾下<code>Promise</code>用法：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> promise = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve,reject</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (操作成功) &#123;</span><br><span class="line">        resolve(value)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        reject(error)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br><span class="line">promise.then(<span class="function"><span class="keyword">function</span> (<span class="params">value</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// success</span></span><br><span class="line">&#125;,<span class="function"><span class="keyword">function</span> (<span class="params">value</span>) </span>&#123;</span><br><span class="line">    <span class="comment">// failure</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<h3 id="8-2-面试够用版"><a href="#8-2-面试够用版" class="headerlink" title="8.2 面试够用版"></a>8.2 面试够用版</h3><blockquote>
<p>来源：<a href="https://link.juejin.im?target=https%3A%2F%2Fgithub.com%2Fforthealllight%2Fblog%2Fissues%2F4" target="_blank" rel="noopener">实现一个完美符合Promise/A+规范的Promise</a></p>
</blockquote>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">myPromise</span>(<span class="params">constructor</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">let</span> self=<span class="keyword">this</span>;</span><br><span class="line">    self.status=<span class="string">"pending"</span> <span class="comment">//定义状态改变前的初始状态</span></span><br><span class="line">    self.value=<span class="literal">undefined</span>;<span class="comment">//定义状态为resolved的时候的状态</span></span><br><span class="line">    self.reason=<span class="literal">undefined</span>;<span class="comment">//定义状态为rejected的时候的状态</span></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">resolve</span>(<span class="params">value</span>)</span>&#123;</span><br><span class="line">        <span class="comment">//两个==="pending"，保证了状态的改变是不可逆的</span></span><br><span class="line">       <span class="keyword">if</span>(self.status===<span class="string">"pending"</span>)&#123;</span><br><span class="line">          self.value=value;</span><br><span class="line">          self.status=<span class="string">"resolved"</span>;</span><br><span class="line">       &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">reject</span>(<span class="params">reason</span>)</span>&#123;</span><br><span class="line">        <span class="comment">//两个==="pending"，保证了状态的改变是不可逆的</span></span><br><span class="line">       <span class="keyword">if</span>(self.status===<span class="string">"pending"</span>)&#123;</span><br><span class="line">          self.reason=reason;</span><br><span class="line">          self.status=<span class="string">"rejected"</span>;</span><br><span class="line">       &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//捕获构造异常</span></span><br><span class="line">    <span class="keyword">try</span>&#123;</span><br><span class="line">       <span class="keyword">constructor</span>(resolve,reject);</span><br><span class="line">    &#125;catch(e)&#123;</span><br><span class="line">       reject(e);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>同时，需要在<code>myPromise</code>的原型上定义链式调用的<code>then</code>方法：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">myPromise.prototype.then=<span class="function"><span class="keyword">function</span>(<span class="params">onFullfilled,onRejected</span>)</span>&#123;</span><br><span class="line">   <span class="keyword">let</span> self=<span class="keyword">this</span>;</span><br><span class="line">   <span class="keyword">switch</span>(self.status)&#123;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">"resolved"</span>:</span><br><span class="line">        onFullfilled(self.value);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">case</span> <span class="string">"rejected"</span>:</span><br><span class="line">        onRejected(self.reason);</span><br><span class="line">        <span class="keyword">break</span>;</span><br><span class="line">      <span class="keyword">default</span>:       </span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>测试一下：</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> p=<span class="keyword">new</span> myPromise(<span class="function"><span class="keyword">function</span>(<span class="params">resolve,reject</span>)</span>&#123;resolve(<span class="number">1</span>)&#125;);</span><br><span class="line">p.then(<span class="function"><span class="keyword">function</span>(<span class="params">x</span>)</span>&#123;<span class="built_in">console</span>.log(x)&#125;)</span><br><span class="line"><span class="comment">//输出1</span></span><br></pre></td></tr></table></figure>
<h3 id="8-3-大厂专供版"><a href="#8-3-大厂专供版" class="headerlink" title="8.3 大厂专供版"></a>8.3 大厂专供版</h3><p>直接贴出来吧，这个版本还算好理解</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> PENDING = <span class="string">"pending"</span>;</span><br><span class="line"><span class="keyword">const</span> FULFILLED = <span class="string">"fulfilled"</span>;</span><br><span class="line"><span class="keyword">const</span> REJECTED = <span class="string">"rejected"</span>;</span><br><span class="line">    </span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Promise</span>(<span class="params">excutor</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> that = <span class="keyword">this</span>; <span class="comment">// 缓存当前promise实例对象</span></span><br><span class="line">    that.status = PENDING; <span class="comment">// 初始状态</span></span><br><span class="line">    that.value = <span class="literal">undefined</span>; <span class="comment">// fulfilled状态时 返回的信息</span></span><br><span class="line">    that.reason = <span class="literal">undefined</span>; <span class="comment">// rejected状态时 拒绝的原因</span></span><br><span class="line">    that.onFulfilledCallbacks = []; <span class="comment">// 存储fulfilled状态对应的onFulfilled函数</span></span><br><span class="line">    that.onRejectedCallbacks = []; <span class="comment">// 存储rejected状态对应的onRejected函数</span></span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">resolve</span>(<span class="params">value</span>) </span>&#123; <span class="comment">// value成功态时接收的终值</span></span><br><span class="line">        <span class="keyword">if</span>(value <span class="keyword">instanceof</span> <span class="built_in">Promise</span>) &#123;</span><br><span class="line">            <span class="keyword">return</span> value.then(resolve, reject);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="comment">// 实践中要确保 onFulfilled 和 onRejected 方法异步执行，且应该在 then 方法被调用的那一轮事件循环之后的新执行栈中执行。</span></span><br><span class="line">        setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="comment">// 调用resolve 回调对应onFulfilled函数</span></span><br><span class="line">            <span class="keyword">if</span> (that.status === PENDING) &#123;</span><br><span class="line">                <span class="comment">// 只能由pending状态 =&gt; fulfilled状态 (避免调用多次resolve reject)</span></span><br><span class="line">                that.status = FULFILLED;</span><br><span class="line">                that.value = value;</span><br><span class="line">                that.onFulfilledCallbacks.forEach(<span class="function"><span class="params">cb</span> =&gt;</span> cb(that.value));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">reject</span>(<span class="params">reason</span>) </span>&#123; <span class="comment">// reason失败态时接收的拒因</span></span><br><span class="line">        setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="comment">// 调用reject 回调对应onRejected函数</span></span><br><span class="line">            <span class="keyword">if</span> (that.status === PENDING) &#123;</span><br><span class="line">                <span class="comment">// 只能由pending状态 =&gt; rejected状态 (避免调用多次resolve reject)</span></span><br><span class="line">                that.status = REJECTED;</span><br><span class="line">                that.reason = reason;</span><br><span class="line">                that.onRejectedCallbacks.forEach(<span class="function"><span class="params">cb</span> =&gt;</span> cb(that.reason));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 捕获在excutor执行器中抛出的异常</span></span><br><span class="line">    <span class="comment">// new Promise((resolve, reject) =&gt; &#123;</span></span><br><span class="line">    <span class="comment">//     throw new Error('error in excutor')</span></span><br><span class="line">    <span class="comment">// &#125;)</span></span><br><span class="line">    <span class="keyword">try</span> &#123;</span><br><span class="line">        excutor(resolve, reject);</span><br><span class="line">    &#125; <span class="keyword">catch</span> (e) &#123;</span><br><span class="line">        reject(e);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="built_in">Promise</span>.prototype.then = <span class="function"><span class="keyword">function</span>(<span class="params">onFulfilled, onRejected</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">const</span> that = <span class="keyword">this</span>;</span><br><span class="line">    <span class="keyword">let</span> newPromise;</span><br><span class="line">    <span class="comment">// 处理参数默认值 保证参数后续能够继续执行</span></span><br><span class="line">    onFulfilled =</span><br><span class="line">        <span class="keyword">typeof</span> onFulfilled === <span class="string">"function"</span> ? onFulfilled : <span class="function"><span class="params">value</span> =&gt;</span> value;</span><br><span class="line">    onRejected =</span><br><span class="line">        <span class="keyword">typeof</span> onRejected === <span class="string">"function"</span> ? onRejected : <span class="function"><span class="params">reason</span> =&gt;</span> &#123;</span><br><span class="line">            <span class="keyword">throw</span> reason;</span><br><span class="line">        &#125;;</span><br><span class="line">    <span class="keyword">if</span> (that.status === FULFILLED) &#123; <span class="comment">// 成功态</span></span><br><span class="line">        <span class="keyword">return</span> newPromise = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">            setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">                <span class="keyword">try</span>&#123;</span><br><span class="line">                    <span class="keyword">let</span> x = onFulfilled(that.value);</span><br><span class="line">                    resolvePromise(newPromise, x, resolve, reject); <span class="comment">// 新的promise resolve 上一个onFulfilled的返回值</span></span><br><span class="line">                &#125; <span class="keyword">catch</span>(e) &#123;</span><br><span class="line">                    reject(e); <span class="comment">// 捕获前面onFulfilled中抛出的异常 then(onFulfilled, onRejected);</span></span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;)</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (that.status === REJECTED) &#123; <span class="comment">// 失败态</span></span><br><span class="line">        <span class="keyword">return</span> newPromise = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">            setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="keyword">let</span> x = onRejected(that.reason);</span><br><span class="line">                    resolvePromise(newPromise, x, resolve, reject);</span><br><span class="line">                &#125; <span class="keyword">catch</span>(e) &#123;</span><br><span class="line">                    reject(e);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">if</span> (that.status === PENDING) &#123; <span class="comment">// 等待态</span></span><br><span class="line">        <span class="comment">// 当异步调用resolve/rejected时 将onFulfilled/onRejected收集暂存到集合中</span></span><br><span class="line">        <span class="keyword">return</span> newPromise = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">            that.onFulfilledCallbacks.push(<span class="function">(<span class="params">value</span>) =&gt;</span> &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="keyword">let</span> x = onFulfilled(value);</span><br><span class="line">                    resolvePromise(newPromise, x, resolve, reject);</span><br><span class="line">                &#125; <span class="keyword">catch</span>(e) &#123;</span><br><span class="line">                    reject(e);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">            that.onRejectedCallbacks.push(<span class="function">(<span class="params">reason</span>) =&gt;</span> &#123;</span><br><span class="line">                <span class="keyword">try</span> &#123;</span><br><span class="line">                    <span class="keyword">let</span> x = onRejected(reason);</span><br><span class="line">                    resolvePromise(newPromise, x, resolve, reject);</span><br><span class="line">                &#125; <span class="keyword">catch</span>(e) &#123;</span><br><span class="line">                    reject(e);</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;);</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>
<p>emmm，我还是乖乖地写回进阶版吧。</p>
<h2 id="9-手写防抖-Debouncing-和节流-Throttling"><a href="#9-手写防抖-Debouncing-和节流-Throttling" class="headerlink" title="9. 手写防抖(Debouncing)和节流(Throttling)"></a>9. 手写防抖(<code>Debouncing</code>)和节流(<code>Throttling</code>)</h2><blockquote>
<p><code>scroll</code> 事件本身会触发页面的重新渲染，同时 <code>scroll</code> 事件的 <code>handler</code> 又会被高频度的触发, 因此事件的 <code>handler</code> 内部不应该有复杂操作，例如 <code>DOM</code> 操作就不应该放在事件处理中。 针对此类高频度触发事件问题（例如页面 <code>scroll</code> ，屏幕 <code>resize</code>，监听用户输入等），有两种常用的解决方法，防抖和节流。</p>
</blockquote>
<h3 id="9-1-防抖-Debouncing-实现"><a href="#9-1-防抖-Debouncing-实现" class="headerlink" title="9.1 防抖(Debouncing)实现"></a>9.1 防抖(<code>Debouncing</code>)实现</h3><p>典型例子：限制 鼠标连击 触发。</p>
<p>一个比较好的解释是：</p>
<blockquote>
<p>当一次事件发生后，事件处理器要等一定阈值的时间，如果这段时间过去后 再也没有 事件发生，就处理最后一次发生的事件。假设还差 <code>0.01</code> 秒就到达指定时间，这时又来了一个事件，那么之前的等待作废，需要重新再等待指定时间。</p>
</blockquote>
<p><img src="https://wurh.github.io/images/blogs/20190404/2.jpeg" alt=""></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 防抖动函数</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">debounce</span>(<span class="params">fn,wait=<span class="number">50</span>,immediate</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> timer;</span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">        <span class="keyword">if</span>(immediate) &#123;</span><br><span class="line">            fn.apply(<span class="keyword">this</span>,<span class="built_in">arguments</span>)</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(timer) clearTimeout(timer)</span><br><span class="line">        timer = setTimeout(<span class="function"><span class="params">()</span>=&gt;</span> &#123;</span><br><span class="line">            fn.apply(<span class="keyword">this</span>,<span class="built_in">arguments</span>)</span><br><span class="line">        &#125;,wait)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>结合实例：滚动防抖</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 简单的防抖动函数</span></span><br><span class="line"><span class="comment">// 实际想绑定在 scroll 事件上的 handler</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">realFunc</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">"Success"</span>);</span><br><span class="line">&#125;</span><br><span class="line">    </span><br><span class="line"><span class="comment">// 采用了防抖动</span></span><br><span class="line"><span class="built_in">window</span>.addEventListener(<span class="string">'scroll'</span>,debounce(realFunc,<span class="number">500</span>));</span><br><span class="line"><span class="comment">// 没采用防抖动</span></span><br><span class="line"><span class="built_in">window</span>.addEventListener(<span class="string">'scroll'</span>,realFunc);</span><br></pre></td></tr></table></figure>
<h3 id="9-2-节流-Throttling-实现"><a href="#9-2-节流-Throttling-实现" class="headerlink" title="9.2 节流(Throttling)实现"></a>9.2 节流(<code>Throttling</code>)实现</h3><blockquote>
<p>可以理解为事件在一个管道中传输，加上这个节流阀以后，事件的流速就会减慢。实际上这个函数的作用就是如此，它可以将一个函数的调用频率限制在一定阈值内，例如 1s，那么 1s 内这个函数一定不会被调用两次</p>
</blockquote>
<p><img src="https://wurh.github.io/images/blogs/20190404/3.jpeg" alt=""></p>
<p>简单的节流函数:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">throttle</span>(<span class="params">fn, wait</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">let</span> prev = <span class="keyword">new</span> <span class="built_in">Date</span>();</span><br><span class="line">    <span class="keyword">return</span> <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123; </span><br><span class="line">        <span class="keyword">const</span> args = <span class="built_in">arguments</span>;</span><br><span class="line">        <span class="keyword">const</span> now = <span class="keyword">new</span> <span class="built_in">Date</span>();</span><br><span class="line">        <span class="keyword">if</span> (now - prev &gt; wait) &#123;</span><br><span class="line">            fn.apply(<span class="keyword">this</span>, args);</span><br><span class="line">            prev = <span class="keyword">new</span> <span class="built_in">Date</span>();</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<h3 id="9-3-结合实践"><a href="#9-3-结合实践" class="headerlink" title="9.3 结合实践"></a>9.3 结合实践</h3><p><strong>通过第三个参数来切换模式。</strong></p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> throttle = <span class="function"><span class="keyword">function</span>(<span class="params">fn, delay, isDebounce</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> timer</span><br><span class="line">  <span class="keyword">let</span> lastCall = <span class="number">0</span></span><br><span class="line">  <span class="keyword">return</span> <span class="function"><span class="keyword">function</span> (<span class="params">...args</span>) </span>&#123;</span><br><span class="line">    <span class="keyword">if</span> (isDebounce) &#123;</span><br><span class="line">      <span class="keyword">if</span> (timer) clearTimeout(timer)</span><br><span class="line">      timer = setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        fn(...args)</span><br><span class="line">      &#125;, delay)</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="keyword">const</span> now = <span class="keyword">new</span> <span class="built_in">Date</span>().getTime()</span><br><span class="line">      <span class="keyword">if</span> (now - lastCall &lt; delay) <span class="keyword">return</span></span><br><span class="line">      lastCall = now</span><br><span class="line">      fn(...args)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="10-手写一个JS深拷贝"><a href="#10-手写一个JS深拷贝" class="headerlink" title="10. 手写一个JS深拷贝"></a>10. 手写一个JS深拷贝</h2><p>有个最著名的乞丐版实现，在《你不知道的JavaScript（上）》里也有提及：</p>
<h3 id="10-1-乞丐版"><a href="#10-1-乞丐版" class="headerlink" title="10.1 乞丐版"></a>10.1 乞丐版</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> newObj = <span class="built_in">JSON</span>.parse( <span class="built_in">JSON</span>.stringify( someObj ) );</span><br></pre></td></tr></table></figure>
<h3 id="10-2-面试够用版"><a href="#10-2-面试够用版" class="headerlink" title="10.2 面试够用版"></a>10.2 面试够用版</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">deepCopy</span>(<span class="params">obj</span>)</span>&#123;</span><br><span class="line">    <span class="comment">//判断是否是简单数据类型，</span></span><br><span class="line">    <span class="keyword">if</span>(<span class="keyword">typeof</span> obj == <span class="string">"object"</span>)&#123;</span><br><span class="line">        <span class="comment">//复杂数据类型</span></span><br><span class="line">        <span class="keyword">var</span> result = obj.constructor == <span class="built_in">Array</span> ? [] : &#123;&#125;;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">let</span> i <span class="keyword">in</span> obj)&#123;</span><br><span class="line">            result[i] = <span class="keyword">typeof</span> obj[i] == <span class="string">"object"</span> ? deepCopy(obj[i]) : obj[i];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">//简单数据类型 直接 == 赋值</span></span><br><span class="line">        <span class="keyword">var</span> result = obj;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="11-实现一个instanceOf"><a href="#11-实现一个instanceOf" class="headerlink" title="11.实现一个instanceOf"></a>11.实现一个<code>instanceOf</code></h2><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">instanceOf</span>(<span class="params">left,right</span>) </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">let</span> proto = left.__proto__;</span><br><span class="line">    <span class="keyword">let</span> prototype = right.prototype</span><br><span class="line">    <span class="keyword">while</span>(<span class="literal">true</span>) &#123;</span><br><span class="line">        <span class="keyword">if</span>(proto === <span class="literal">null</span>) <span class="keyword">return</span> <span class="literal">false</span></span><br><span class="line">        <span class="keyword">if</span>(proto === prototype) <span class="keyword">return</span> <span class="literal">true</span></span><br><span class="line">        proto = proto.__proto__;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
      
    </div>

    <div>
      
        

      
    </div>

    <div>
      
        
  <div style="padding: 10px 0; margin: 20px auto; width: 90%; text-align: center;">
    <div>坚持原创技术分享，您的支持将鼓励我继续创作！</div>
    <button id="rewardButton" disable="enable" onclick="var qr = document.getElementById('QR'); if (qr.style.display === 'none') {qr.style.display='block';} else {qr.style.display='none'}">
      <span>赏</span>
    </button>
    <div id="QR" style="display: none;">
      
        <div id="wechat" style="display: inline-block">
          <img id="wechat_qr" src="https://wurh.github.io/images/others/weixinshou.png" alt="华Ing WeChat Pay"/>
          <p>微信打赏</p>
        </div>
      
      
        <div id="alipay" style="display: inline-block">
          <img id="alipay_qr" src="https://wurh.github.io/images/others/alifu.png" alt="华Ing Alipay"/>
          <p>支付宝打赏</p>
        </div>
      
    </div>
  </div>


      
    </div>

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/前端-知识-面试/" rel="tag">#前端 知识 面试</a>
          
        </div>
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2019/03/30/20190403/" rel="next" title="前端面试《第六篇》 JS继承">
                <i class="fa fa-chevron-left"></i> 前端面试《第六篇》 JS继承
              </a>
            
          </div>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2019/03/31/201903300749/" rel="prev" title="前端面试《第八篇》 用户输入URL回车后，浏览器做了什么？">
                前端面试《第八篇》 用户输入URL回车后，浏览器做了什么？ <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </article>



    <div class="post-spread">
      
        
<script>
  with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='//bdimg.share.baidu.com/static/api/js/share.js?cdnversion='+~(-new Date()/36e5)];
</script>

      
    </div>
  </div>


          </div>
          


          
  <div class="comments" id="comments">
    
      <div class="ds-thread" data-thread-key="2019/03/31/20190404/"
           data-title="前端面试《第七篇》手写js常考知识" data-url="http://wurh.github.io/2019/03/31/20190404/">
      </div>
    
  </div>


        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap" >
            Table of Contents
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview">
            Overview
          </li>
        </ul>
      

      <section class="site-overview sidebar-panel ">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="//schema.org/Person">
          <img class="site-author-image" itemprop="image"
               src="https://wurh.github.io/images/avatar/logo.jpg?123456"
               alt="华Ing" />
          <p class="site-author-name" itemprop="name">华Ing</p>
          <p class="site-description motion-element" itemprop="description">harder and harder</p>
        </div>
        <nav class="site-state motion-element">
          <div class="site-state-item site-state-posts">
            <a href="/archives">
              <span class="site-state-item-count">56</span>
              <span class="site-state-item-name">posts</span>
            </a>
          </div>

          
            <div class="site-state-item site-state-categories">
              <a href="/categories">
                <span class="site-state-item-count">11</span>
                <span class="site-state-item-name">categories</span>
              </a>
            </div>
          

          
            <div class="site-state-item site-state-tags">
              <a href="/tags">
                <span class="site-state-item-count">15</span>
                <span class="site-state-item-name">tags</span>
              </a>
            </div>
          

        </nav>

        

        <div class="links-of-author motion-element">
          
            
              <span class="links-of-author-item">
                <a href="https://github.com/wurh" target="_blank" title="GitHub">
                  
                    <i class="fa fa-fw fa-github"></i>
                  
                  GitHub
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="http://weibo.com/1674582564/profile?topnav=1&wvr=6" target="_blank" title="微博">
                  
                    <i class="fa fa-fw fa-globe"></i>
                  
                  微博
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="https://www.zhihu.com/people/wu-rong-hua-56" target="_blank" title="知乎">
                  
                    <i class="fa fa-fw fa-globe"></i>
                  
                  知乎
                </a>
              </span>
            
          
        </div>

        
        

        
        
          <div class="links-of-blogroll motion-element links-of-blogroll-inline">
            <div class="links-of-blogroll-title">
              <i class="fa  fa-fw fa-globe"></i>
              Links
            </div>
            <ul class="links-of-blogroll-list">
              
                <li class="links-of-blogroll-item">
                  <a href="http://fsiaonma.github.io/" title="sam博客" target="_blank">sam博客</a>
                </li>
              
                <li class="links-of-blogroll-item">
                  <a href="http://shenjoel.github.io/" title="joel博客" target="_blank">joel博客</a>
                </li>
              
                <li class="links-of-blogroll-item">
                  <a href="http://firewood1122.github.io" title="firewood博客" target="_blank">firewood博客</a>
                </li>
              
                <li class="links-of-blogroll-item">
                  <a href="http://reqianduan.com" title="热前端" target="_blank">热前端</a>
                </li>
              
                <li class="links-of-blogroll-item">
                  <a href="http://opentutorial.info/" title="黄超博客" target="_blank">黄超博客</a>
                </li>
              
            </ul>
          </div>
        

      </section>

      
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">
            
              
            
            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-实现一个new操作符"><span class="nav-number">1.</span> <span class="nav-text">1. 实现一个new操作符</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-实现一个JSON-stringify"><span class="nav-number">2.</span> <span class="nav-text">2. 实现一个JSON.stringify</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-实现一个JSON-parse"><span class="nav-number">3.</span> <span class="nav-text">3. 实现一个JSON.parse</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#3-1-第一种：直接调用-eval"><span class="nav-number">3.1.</span> <span class="nav-text">3.1 第一种：直接调用 eval</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#3-2-第二种：Function"><span class="nav-number">3.2.</span> <span class="nav-text">3.2 第二种：Function</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#4-实现一个call或-apply"><span class="nav-number">4.</span> <span class="nav-text">4. 实现一个call或 apply</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-Function-call按套路实现"><span class="nav-number">4.1.</span> <span class="nav-text">4.1 Function.call按套路实现</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-1-简单版"><span class="nav-number">4.2.</span> <span class="nav-text">4.1.1 简单版</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-1-2-完善版"><span class="nav-number">4.3.</span> <span class="nav-text">4.1.2 完善版</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#4-2-Function-apply的模拟实现"><span class="nav-number">4.4.</span> <span class="nav-text">4.2 Function.apply的模拟实现</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#5-实现一个Function-bind"><span class="nav-number">5.</span> <span class="nav-text">5. 实现一个Function.bind()</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#6-实现一个继承"><span class="nav-number">6.</span> <span class="nav-text">6. 实现一个继承</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#7-实现一个JS函数柯里化"><span class="nav-number">7.</span> <span class="nav-text">7. 实现一个JS函数柯里化</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#7-1-通用版"><span class="nav-number">7.1.</span> <span class="nav-text">7.1 通用版</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#7-2-ES6骚写法"><span class="nav-number">7.2.</span> <span class="nav-text">7.2 ES6骚写法</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#8-手写一个Promise-中高级必考"><span class="nav-number">8.</span> <span class="nav-text">8. 手写一个Promise(中高级必考)</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#8-1-Promise的流程图分析"><span class="nav-number">8.1.</span> <span class="nav-text">8.1 Promise的流程图分析</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#8-2-面试够用版"><span class="nav-number">8.2.</span> <span class="nav-text">8.2 面试够用版</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#8-3-大厂专供版"><span class="nav-number">8.3.</span> <span class="nav-text">8.3 大厂专供版</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#9-手写防抖-Debouncing-和节流-Throttling"><span class="nav-number">9.</span> <span class="nav-text">9. 手写防抖(Debouncing)和节流(Throttling)</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#9-1-防抖-Debouncing-实现"><span class="nav-number">9.1.</span> <span class="nav-text">9.1 防抖(Debouncing)实现</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#9-2-节流-Throttling-实现"><span class="nav-number">9.2.</span> <span class="nav-text">9.2 节流(Throttling)实现</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#9-3-结合实践"><span class="nav-number">9.3.</span> <span class="nav-text">9.3 结合实践</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#10-手写一个JS深拷贝"><span class="nav-number">10.</span> <span class="nav-text">10. 手写一个JS深拷贝</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#10-1-乞丐版"><span class="nav-number">10.1.</span> <span class="nav-text">10.1 乞丐版</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#10-2-面试够用版"><span class="nav-number">10.2.</span> <span class="nav-text">10.2 面试够用版</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#11-实现一个instanceOf"><span class="nav-number">11.</span> <span class="nav-text">11.实现一个instanceOf</span></a></li></ol></div>
            
          </div>
        </section>
      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy;  2013 - 
  <span itemprop="copyrightYear">2019</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">华Ing</span>
</div>

<div class="powered-by">
  Powered by <a class="theme-link" href="https://hexo.io">Hexo</a>
</div>

<div class="theme-info">
  Theme -
  <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Pisces
  </a>
</div>

        

        
      </div>
    </footer>

    <div class="back-to-top">
      <i class="fa fa-arrow-up"></i>
    </div>
  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  



  
  <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.0.2"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.0.2"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.0.2"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.0.2"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.0.2"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.0.2"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.0.2"></script>



  

  
    
  

  <script type="text/javascript">
    var duoshuoQuery = {short_name:"wurh"};
    (function() {
      var ds = document.createElement('script');
      ds.type = 'text/javascript';ds.async = true;
      ds.id = 'duoshuo-script';
      ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
      ds.charset = 'UTF-8';
      (document.getElementsByTagName('head')[0]
      || document.getElementsByTagName('body')[0]).appendChild(ds);
    })();
  </script>

  
    
    <script src="/lib/ua-parser-js/dist/ua-parser.min.js?v=0.7.9"></script>
    <script src="/js/src/hook-duoshuo.js"></script>
  






  
  

  

  

  

  


</body>
</html>
